package com.zl.quickdoc.framework.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import org.apache.commons.lang3.StringUtils;

import com.zl.quickdoc.constant.QuickDocC;
import com.zl.quickdoc.framework.IApiFramework;
import com.zl.quickdoc.model.ApiAction;
import com.zl.quickdoc.model.ApiField;
import com.zl.quickdoc.model.ApiModule;
import com.zl.quickdoc.model.DocCfgParam;
import com.zl.quickdoc.resolver.JavaTypeRegistrar;
import com.zl.quickdoc.utils.ParserJavaUtils;


/**
 * 获取注释信息
 */
public abstract class AbstractHttpFramework implements IApiFramework {
    
    protected DocCfgParam cfg = new DocCfgParam();
    protected List<String> includePackages = new ArrayList<>();
    protected List<String> excludePackages = new ArrayList<>();
    protected boolean orderFlag = false;
    protected boolean apiOrderFlag=false;
    protected boolean moduleGroupFlag=false;
    
    protected AbstractHttpFramework() {
    }
    protected AbstractHttpFramework(DocCfgParam cfg) {
        if(StringUtils.isNotBlank(cfg.getIncludePackages())){
            this.includePackages= Arrays.asList(cfg.getIncludePackages().split(","));
        }
        if(StringUtils.isNotBlank(cfg.getExcludePackages())){
            this.excludePackages= Arrays.asList(cfg.getExcludePackages().split(","));
        }
        if(cfg.getTypeConvertFlag()){
            if(cfg.getTypeConvertMap().isEmpty()){
                JavaTypeRegistrar.putAllShowType(cfg.getTypeConvertMap());
            }
        }
        this.orderFlag=cfg.getOrderFlag();
        this.apiOrderFlag=cfg.getApiOrderFlag();
        this.moduleGroupFlag=cfg.getModuleGroupFlag();
    }
    @Override
    public boolean matched(String className) {
        if(includePackages.isEmpty() && excludePackages.isEmpty()){
            return true;
        }
        boolean flag=false;
        for(String x:includePackages){
            Pattern p=Pattern.compile(x,Pattern.CASE_INSENSITIVE);
            Matcher m = p.matcher(className);
            if(m.find()){
                flag=true;
                break;
            }
        }
        for(String x:excludePackages){
            Pattern p=Pattern.compile(x,Pattern.CASE_INSENSITIVE);
            Matcher m = p.matcher(className);
            if(m.find()){
                flag=false;
                break;
            }
        }
        return flag;
    }
    
    @Override
    public List<ApiModule> extend(List<ApiModule> apiModules) throws Exception{
        if(apiOrderFlag) {
            Collections.sort(apiModules, new Comparator<ApiModule>(){
                @Override
                public int compare(ApiModule o1, ApiModule o2) {
                    if(o1.getOrderBy()>o2.getOrderBy()) {
                        return 1;
                    }
                    if(o1.getOrderBy()<o2.getOrderBy()) {
                        return -1;
                    }
                    String s1 = o1.getTitle();
                    String s2 = o2.getTitle();
                    return s1.compareTo(s2);
                }
            });
        }
        apiModules.stream().forEach(x->{
            x.setTitle(x.getTitle().replace("<br>", "").replace("\n", ""));
            x.getApiActions().stream().forEach(tax->{
                ApiAction ax = (ApiAction) tax;
                ax.setTitle(ax.getTitle().replace("<br>", "").replace("\n", ""));
                if(StringUtils.isBlank(ax.getTitle())){
                    List<String> uris = ax.getUris();
                    if(uris!=null&&!uris.isEmpty()){
                        ax.setTitle(ax.getUris().get(0));
                    }else{
                        ax.setTitle(ax.getSimpleName());
                    }
                }
                if(tax.getReqParam()!=null) {
                    handlePathFieldAndFieldType(tax.getReqParam());
                }
                if(tax.getResParam()!=null) {
                    handlePathFieldAndFieldType(ax.getResParam());
                }
                
                getPathParam(ax);
                getRequestValue(ax);
                getResponseValue(ax);
            });
            if(apiOrderFlag) {
                Collections.sort(x.getApiActions(), new Comparator<ApiAction>(){
                    @Override
                    public int compare(ApiAction o1, ApiAction o2) {
                        if(o1.getOrderBy()>o2.getOrderBy()) {
                            return 1;
                        }
                        if(o1.getOrderBy()<o2.getOrderBy()) {
                            return -1;
                        }
                        String s1 = o1.getTitle();
                        String s2 = o2.getTitle();
                        return s1.compareTo(s2);
                    }
                });
            }
        });
        if(moduleGroupFlag) {
            List<ApiModule> apiModules2 = new ArrayList<>();
            Map<String,ApiModule> map = new HashMap<>();
            for(ApiModule x:apiModules) {
                if(map.get(x.getTitle()) != null) {
                    ApiModule m = map.get(x.getTitle());
                    m.getApiActions().addAll(x.getApiActions());
                }else {
                    apiModules2.add(x);
                    map.put(x.getTitle(),x);
                }
            }
            return apiModules2;
        }
        
        return apiModules;
    }
    
    private String convertShowType(String type) {
       String ntype= JavaTypeRegistrar.getShowType(ParserJavaUtils.typeHandler(type));
       if(StringUtils.isNotBlank(ntype)){
           return ntype;
       }
       ntype = JavaTypeRegistrar.getShowType("*");
       return ntype!=null?ntype:type;
    }
    private void handlePathFieldAndFieldType(List<ApiField> list) {
        if(list==null || list.isEmpty()) {
            return;
        }
        for(ApiField x:list) {
            x.setTitle(x.getTitle()!=null?x.getTitle().replace("<br>", "").replace("\n", ""):"");
            x.setShowType(convertShowType(x.getFactType()));
            if(x.getChildren()!=null&&x.getChildren().size()>0) {
                handlePathFieldAndFieldType(x.getChildren());
            }
        }
        if(!orderFlag) {
            return;
        }
        Collections.sort(list, new Comparator<ApiField>(){
            @Override
            public int compare(ApiField o1, ApiField o2) {
                boolean isPathFlag1 = o1.getPathFlag();
                boolean isPathFlag2 = o2.getPathFlag();
                // 如果 o1 的 pathFlag 值为 true，且 o2 的 pathFlag 值不为 true，则排在前面
                if (isPathFlag1 && !isPathFlag2) {
                    return -1;
                }
                // 如果 o2 的 pathFlag 值为 true，且 o1 的 pathFlag 值不为 true，则排在后面
                else if (isPathFlag2 && !isPathFlag1) {
                    return 1;
                }
                else {
                    return o1.getName().substring(0,1).compareTo(o2.getName().substring(0,1));
                }
            }
        });
    }
    public void getPathParam(ApiAction ax) {
        List<ApiField> fields = new LinkedList<>();
        if(!ax.getRequestVoid()) {
            fields = ax.getReqParam().stream().filter(x->x.getPathFlag()).collect(Collectors.toList());
        }
        ax.setPathParam(fields);
    }
    
    public void getRequestValue(ApiAction ax) {
        if(ax.getRequestVoid()) {
            ax.setRequestValue("");
            ax.setRequestValueSimple("");
            return;
        }
        StringBuilder buf=new StringBuilder();
        StringBuilder bufsimple=new StringBuilder();
        setFormJson(buf, ax.getReqParam(),"  ",false);
        setFormJson(bufsimple, ax.getReqParam(),"",true);
        ax.setRequestValue(buf.toString());
        ax.setRequestValueSimple(bufsimple.toString().replace("\n",""));
    }
    public void getResponseValue(ApiAction ax) {
        if(ax.getResponseVoid()) {
            ax.setResponseValue("");
            ax.setResponseValueSimple("");
            return;
        }
        StringBuilder buf=new StringBuilder();
        StringBuilder bufsimple=new StringBuilder();
        if(QuickDocC.TYPE_STREAM.equals(ax.getDataType())){
            buf.append("文件下载");
            bufsimple.append("文件下载");
        }else {
            setFormJson(buf, ax.getResParam(),"  ",false);
            setFormJson(bufsimple, ax.getResParam(),"  ",true);
        }
        ax.setResponseValue(buf.toString());
        ax.setResponseValueSimple(bufsimple.toString().replace("\n",""));
    }
    
    protected void setFormJson(StringBuilder buf, List<ApiField> fields, String blankstr, boolean simpleFlag) {
        if(fields==null || fields.isEmpty()){
            return;
        }
        int idx=0;
        for(ApiField fieldx:fields){
            List<ApiField> childrens = fieldx.getChildren();
            if(childrens!=null&&childrens.size()>0){
                if(!fieldx.getAnonymousFlag() && StringUtils.isNotBlank(fieldx.getFactName())) {
                    if(simpleFlag){
                        buf.append("\n"+blankstr+"\""+fieldx.getName()+"\": ");
                    }else{
//                        System.out.println(fieldx.getName()+"|"+fieldx.getFactType()+"|"+fieldx.getTitle());
                        buf.append("\n"+blankstr+"\""+fieldx.getName()+QuickDocC.KEY_SPLIT_CHAR+fieldx.getTitle().replace("\"", "&quot;")+"  | "+fieldx.getRequire()+"\": ");
                    }
                }else {
                    buf.append(!fieldx.getSimpleValueFlag()?"\n" +blankstr:"");
                }
                if("Arrays".equals(fieldx.getFactType())){
                    buf.append("[");
                }
                else if("Objects".equals(fieldx.getFactType()) || "Map".equals(fieldx.getFactType())){
                    buf.append("{");
                }
                setFormJson(buf, childrens, !fieldx.getSimpleValueFlag()?blankstr + "  ":"" ,simpleFlag);
                if("Arrays".equals(fieldx.getFactType())){
                    buf.append((!fieldx.getSimpleValueFlag()?"\n" +blankstr:"")+"]");
                }
                else if("Objects".equals(fieldx.getFactType()) || "Map".equals(fieldx.getFactType())){
                    buf.append("\n"+blankstr+"}");
                }
                if(idx<fields.size()-1){
                    buf.append(", ");
                }
            }else{
                if(!fieldx.getAnonymousFlag() && StringUtils.isNotBlank(fieldx.getFactName())) {
                    if(simpleFlag){
                        buf.append(String.format("\n"+blankstr+"\"%s\": ",fieldx.getName()));
                    }else{
                        buf.append(String.format("\n"+blankstr+"\"%s\": ",fieldx.getName()+QuickDocC.KEY_SPLIT_CHAR+fieldx.getTitle().replace("\"", "&quot;")+"  | "+fieldx.getRequire()));
                    }
                }else{
                    buf.append(!fieldx.getSimpleValueFlag()?"\n"+blankstr:"");
                }
                if("Objects".equals(fieldx.getFactType())){
                    if(StringUtils.isNotBlank(fieldx.getDefaultValue())){
                        if(fieldx.getDefaultValue().startsWith("\"")){
                            buf.append(fieldx.getDefaultValue());
                        }else {
                            buf.append(ParserJavaUtils.defaultValueHandler(fieldx));
                        }
                    }else{
                        buf.append("{}");
                    }
                }else{
                    buf.append(ParserJavaUtils.defaultValueHandler(fieldx));
                }
                if(idx<fields.size()-1){
                    buf.append(", ");
                }
            }
            idx++;
        }
    }
    
    
}
